/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Almex
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
package be.raildelays.domain.xls;
import be.raildelays.domain.Sens;
import be.raildelays.domain.entities.Station;
import be.raildelays.domain.entities.TrainLine;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import javax.persistence.*;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
/**
* Describe a row in the delays Excel workbook.
*
* @author Almex
*/
@Entity
@Table(name = "EXCEL_ROW", uniqueConstraints = @UniqueConstraint(columnNames = {
"DATE", "SENS"}))
public class ExcelRow<T extends ExcelRow> implements Comparable<T>, Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "ID")
private Long id;
@Column(name = "DATE")
@NotNull
//FIXME @Past cannot use JSR-310 (java.time.* API) in conjunction with JSR-349 (Bean Validation 1.1)
private LocalDate date;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "ARRIVAL_STATION_ID")
@NotNull
private Station arrivalStation;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "DEPARTURE_STATION_ID")
@NotNull
private Station departureStation;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "LINK_STATION_ID")
private Station linkStation;
@Column(name = "EXPECTED_DEPARTURE_TIME")
@NotNull
//FIXME @Past cannot use JSR-310 (java.time.* API) in conjunction with JSR-349 (Bean Validation 1.1)
private LocalTime expectedDepartureTime;
@Column(name = "EXPECTED_ARRIVAL_TIME")
@NotNull
//FIXME @Past cannot use JSR-310 (java.time.* API) in conjunction with JSR-349 (Bean Validation 1.1)
private LocalTime expectedArrivalTime;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "EXPEXTED_TRAIN1_ID")
@NotNull
private TrainLine expectedTrainLine1;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "EXPEXTED_TRAIN2_ID")
private TrainLine expectedTrainLine2;
@Column(name = "EFFECTIVE_DEPARTURE_TIME")
@NotNull
//FIXME @Past cannot use JSR-310 (java.time.* API) in conjunction with JSR-349 (Bean Validation 1.1)
private LocalTime effectiveDepartureTime;
@Column(name = "EFFECTIVE_ARRIVAL_TIME")
@NotNull
//FIXME @Past cannot use JSR-310 (java.time.* API) in conjunction with JSR-349 (Bean Validation 1.1)
private LocalTime effectiveArrivalTime;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "EFFECTIVE_TRAIN1_ID")
@NotNull
private TrainLine effectiveTrainLine1;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "EFFECTIVE_TRAIN2_ID")
private TrainLine effectiveTrainLine2;
@Column(name = "DELAY")
@Min(0)
private Long delay;
@Column(name = "SENS")
private Sens sens;
protected ExcelRow(final Builder builder) {
this.date = builder.date;
this.arrivalStation = builder.arrivalStation;
this.departureStation = builder.departureStation;
this.linkStation = builder.linkStation;
this.expectedDepartureTime = builder.expectedDepartureTime;
this.expectedArrivalTime = builder.expectedArrivalTime;
this.expectedTrainLine1 = builder.expectedTrainLine1;
this.expectedTrainLine2 = builder.expectedTrainLine2;
this.effectiveDepartureTime = builder.effectiveDepartureTime;
this.effectiveArrivalTime = builder.effectiveArrivalTime;
this.effectiveTrainLine1 = builder.effectiveTrainLine1;
this.effectiveTrainLine2 = builder.effectiveTrainLine2;
this.delay = builder.delay;
this.sens = builder.sens;
}
protected static String notNullToString(Object obj) {
String result = "";
if (obj != null) {
result = StringUtils.trimToEmpty(obj.toString());
}
return result;
}
@Override
public int compareTo(T excelRow) {
int result;
if (excelRow == this) {
result = 0;
} else if (excelRow == null) {
result = 1;
} else {
// We give only a chronological order based on expectedTime time
result = new CompareToBuilder()
.append(this.getDate(), excelRow.getDate())
.append(this.getExpectedDepartureTime(), excelRow.getExpectedDepartureTime())
.append(this.getExpectedArrivalTime(), excelRow.getExpectedArrivalTime())
.toComparison();
}
return result;
}
public LocalDate getDate() {
return date;
}
public Station getArrivalStation() {
return arrivalStation;
}
public Station getDepartureStation() {
return departureStation;
}
public Station getLinkStation() {
return linkStation;
}
public LocalTime getExpectedDepartureTime() {
return expectedDepartureTime;
}
public LocalTime getExpectedArrivalTime() {
return expectedArrivalTime;
}
public TrainLine getExpectedTrainLine1() {
return expectedTrainLine1;
}
public TrainLine getExpectedTrainLine2() {
return expectedTrainLine2;
}
public LocalTime getEffectiveDepartureTime() {
return effectiveDepartureTime;
}
public LocalTime getEffectiveArrivalTime() {
return effectiveArrivalTime;
}
public TrainLine getEffectiveTrainLine1() {
return effectiveTrainLine1;
}
public TrainLine getEffectiveTrainLine2() {
return effectiveTrainLine2;
}
public Long getDelay() {
return delay;
}
public Sens getSens() {
return sens;
}
public Long getId() {
return id;
}
@Override
public int hashCode() {
return new HashCodeBuilder() //
.append("date") //
.append("arrivalStation") //
.append("departureStation") //
.append("linkStation") //
.append("expectedTrainLine1") //
.append("expectedTrainLine2") //
.hashCode();
}
@Override
public boolean equals(Object obj) {
boolean result = false;
if (obj == this) {
result = true;
} else if (obj instanceof ExcelRow) {
ExcelRow target = (ExcelRow) obj;
result = new EqualsBuilder() //
.append(this.date, target.date) //
.append(this.arrivalStation, target.arrivalStation) //
.append(this.departureStation, target.departureStation) //
.append(this.linkStation, target.linkStation) //
.append(this.expectedTrainLine1, target.expectedTrainLine1) //
.append(this.expectedTrainLine2, target.expectedTrainLine2) //
.isEquals();
}
return result;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(date != null ? date.format(DateTimeFormatter.ISO_DATE) : "N/A");
builder.append(" ");
builder.append(notNullToString(departureStation));
builder.append(" ");
builder.append(notNullToString(arrivalStation));
builder.append(" ");
builder.append(notNullToString(linkStation));
builder.append(" ");
builder.append(expectedDepartureTime != null ? expectedDepartureTime.format(DateTimeFormatter.ISO_TIME) : "N/A");
builder.append(" ");
builder.append(expectedArrivalTime != null ? expectedArrivalTime.format(DateTimeFormatter.ISO_TIME) : "N/A");
builder.append(" ");
builder.append(notNullToString(expectedTrainLine1));
builder.append(" ");
builder.append(notNullToString(expectedTrainLine2));
builder.append(" ");
builder.append(effectiveDepartureTime != null ? effectiveDepartureTime.format(DateTimeFormatter.ISO_TIME) : "N/A");
builder.append(" ");
builder.append(effectiveArrivalTime != null ? effectiveArrivalTime.format(DateTimeFormatter.ISO_TIME) : "N/A");
builder.append(" ");
builder.append(notNullToString(effectiveTrainLine1));
builder.append(" ");
builder.append(notNullToString(effectiveTrainLine2));
builder.append(" ");
builder.append(delay);
builder.append(" ");
builder.append(sens);
return builder.toString();
}
public static class Builder {
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
protected final LocalDate date;
protected final Sens sens;
protected Station arrivalStation;
protected Station departureStation;
protected Station linkStation;
protected LocalTime expectedDepartureTime;
protected LocalTime expectedArrivalTime;
protected TrainLine expectedTrainLine1;
protected TrainLine expectedTrainLine2;
protected LocalTime effectiveDepartureTime;
protected LocalTime effectiveArrivalTime;
protected TrainLine effectiveTrainLine1;
protected TrainLine effectiveTrainLine2;
protected Long delay;
public Builder(final LocalDate date, final Sens sens) {
this.date = date;
this.sens = sens;
}
public Builder(ExcelRow excelRow) {
this.date = excelRow.date;
this.arrivalStation = excelRow.arrivalStation;
this.departureStation = excelRow.departureStation;
this.linkStation = excelRow.linkStation;
this.expectedDepartureTime = excelRow.expectedDepartureTime;
this.expectedArrivalTime = excelRow.expectedArrivalTime;
this.expectedTrainLine1 = excelRow.expectedTrainLine1;
this.expectedTrainLine2 = excelRow.expectedTrainLine2;
this.effectiveDepartureTime = excelRow.effectiveDepartureTime;
this.effectiveArrivalTime = excelRow.effectiveArrivalTime;
this.effectiveTrainLine1 = excelRow.effectiveTrainLine1;
this.effectiveTrainLine2 = excelRow.effectiveTrainLine2;
this.delay = excelRow.delay;
this.sens = excelRow.sens;
}
public Builder arrivalStation(final Station arrivalStation) {
this.arrivalStation = arrivalStation;
return this;
}
public Builder departureStation(final Station departureStation) {
this.departureStation = departureStation;
return this;
}
public Builder linkStation(final Station linkStation) {
this.linkStation = linkStation;
return this;
}
public Builder expectedDepartureTime(
final LocalTime expectedDepartureTime) {
this.expectedDepartureTime = expectedDepartureTime;
return this;
}
public Builder expectedArrivalTime(
final LocalTime expectedArrivalTime) {
this.expectedArrivalTime = expectedArrivalTime;
return this;
}
public Builder expectedTrain1(final TrainLine expectedTrainLine1) {
this.expectedTrainLine1 = expectedTrainLine1;
return this;
}
public Builder expectedTrain2(final TrainLine expectedTrainLine2) {
this.expectedTrainLine2 = expectedTrainLine2;
return this;
}
public Builder effectiveDepartureTime(
final LocalTime effectiveDepartureTime) {
this.effectiveDepartureTime = effectiveDepartureTime;
return this;
}
public Builder effectiveArrivalTime(
final LocalTime effectiveArrivalTime) {
this.effectiveArrivalTime = effectiveArrivalTime;
return this;
}
public Builder effectiveTrain1(final TrainLine effectiveTrainLine1) {
this.effectiveTrainLine1 = effectiveTrainLine1;
return this;
}
public Builder effectiveTrain2(final TrainLine effectiveTrainLine2) {
this.effectiveTrainLine2 = effectiveTrainLine2;
return this;
}
public Builder delay(final Long delay) {
this.delay = delay;
return this;
}
public ExcelRow build() {
return build(true);
}
public ExcelRow build(boolean validate) {
ExcelRow result = new ExcelRow(this);
if (validate) {
validate(result);
}
return result;
}
protected void validate(ExcelRow row) {
Set<ConstraintViolation<ExcelRow>> constraintViolations = validator.validate(row);
if (!constraintViolations.isEmpty()) {
StringBuilder builder = new StringBuilder();
for (ConstraintViolation<? extends ExcelRow> constraintViolation : constraintViolations) {
builder.append("\nConstraints violations occurred: ");
builder.append(constraintViolation.getPropertyPath());
builder.append(' ');
builder.append(constraintViolation.getMessage());
}
throw new ValidationException(builder.toString());
}
}
}
}